import { Observer, useLocalStore, useObserver } from 'mobx-react';
import { types, unprotect, onPatch, onAction, getSnapshot, onSnapshot, applySnapshot } from "mobx-state-tree";
import React from 'react';
import { Button } from 'antd';

// declaring the shape of a node with the type `Todo`
const Todo = types.model({
  id: types.identifier,
  title: types.string,
  done: types.boolean,
  assignee: types.optional(types.string, 'nobody'),
}).actions(self => ({
  setTitle(title: string) {
    self.title = title;
  },
  toggle() {
    self.done = !self.done;
  },
}));

const TodoStore = types
  .model("TodoStore", {
    loaded: types.boolean, // 2
    endpoint: "http://localhost", // 3
    todos: types.optional(types.array(Todo), []), // 4
    selectedTodo: types.maybeNull(types.reference(Todo)) // 5
    // selectedTodo: types.maybeNull(Todo) // 5
  })
  .views(self => {
    return {
      get completedTodos() {
        return self.todos.filter(t => t.done)
      },
      findTodosByUser(user: string) {
        return self.todos.filter(t => t.assignee === user)
      }
    }
  })
  .actions(self => {
    return {
      addTodo(title: string) {
        self.todos.push({
          id: String(Math.floor(Math.random() * 1000)),
          title,
          done: false,
          // assignee: 'nobody',
        })
      },
      select(todoId: any) {
        self.selectedTodo = todoId;
      },
    }
  })
  .actions(self => ({
    add3() {
      self.addTodo('study vue');
      self.addTodo('study react');
      self.addTodo('study mobx');
    },
    modifySome() {
      self.todos[0].title = 'change to vue3';
      self.todos[1].setTitle('learn react');
      self.addTodo('study mobx-state-tree');
    }
  }))
  .actions(self => {
    const history = [] as any[];
    let index = -1;
    return {
      afterCreate() {
        // 还可以从后台从数据库加载上次保存的状态
        onSnapshot(self, (js) => {
          if (history.length > index + 1) {
            // 内部前进后退，不记录历史
            return;
          }
          index += 1;
          history[index] = js;
          console.log('on snapshot');
        });
      },
      beforeDestroy() {
        alert('是否要保存状态到数据库服务器？');
      },
      goBack() {
        const previous = history[index - 1];
        if (!previous) {
          alert('已经到最后了');
          return;
        }
        console.log('previous', previous);
        applySnapshot(self, previous);
        index -= 1;
      },
      goNext() {
        index += 1;
        applySnapshot(self, history[index]);
      }
    }
  });

// const todoStore = TodoStore.create({
//   loaded: true,
// });
// // unprotect(todoStore);

// let disposer = onAction(todoStore, (call) => {
//   console.log('action', call);
// });

export default function TodoUI() {
  const todoStore = useLocalStore(() => TodoStore.create({
    loaded: true,
  }));
  return useObserver(() => (
    <div>
      <div>
        <Button type="default" onClick={() => todoStore.add3()}>todoStore.add3()</Button>
        <Button type="default" onClick={todoStore.modifySome}>todoStore.modifySome()</Button>
        <Button type="default" onClick={todoStore.goBack}>todoStore.goBack()</Button>
        <Button type="default" onClick={todoStore.goNext}>todoStore.goNext()</Button>
      </div>
      <ul>
        {todoStore.todos.map(todo => (
          <Observer key={todo.id}>
            {() => (
              <li onClick={todo.toggle}>
                <input type="checkbox" checked={todo.done} />
                <span>{todo.title}</span>
                <button onClick={(e) => { e.stopPropagation(); todoStore.select(todo.id) }}>select me</button>
                {todoStore.selectedTodo === todo ? 'selected' : ''}
              </li>
            )}
          </Observer>
        ))}
      </ul>
      <Observer>
        {() =>
          todoStore.selectedTodo && <pre>selectedTodo: <br />{JSON.stringify(getSnapshot(todoStore.selectedTodo), null, 2)}</pre>
        }
      </Observer>
      <Observer>
        {() => (
          <pre>{JSON.stringify(getSnapshot(todoStore), null, 2)}</pre>
        )}
      </Observer>
    </div >
  ));
}

